<?php

namespace mpend\models;

use common\models\user\UserConnect;
use Yii;
use yii\db\Exception;
use common\models\app\AppToken;
use common\models\app\AppDevice;
use common\models\app\AppClient;
use common\models\app\AppVersion;

/**
 * APP接口访问授权接口
 * Authorization
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 * @property null|string $openid
 * @property null|AppClient|object $client
 * @property null|UserConnect $connect
 */
class AuthorizationForm extends \common\base\Model {

    /**
     * @var string 授权应用ID
     */
    public $appid;

    /**
     * @var string 时间戳
     */
    public $timestamp;

    /**
     * @var string 设备唯一编号
     */
    public $sn;

    /**
     * @var string 客户端操作系统
     */
    public $os;

    /**
     * @var string 设备机型
     */
    public $model;

    /**
     * @var integer 客户端Build版本号
     */
    public $build;

    /**
     * @var string 随机字符串
     */
    public $nonce;

    /**
     * @var string 签名字符串
     */
    public $sign;

    /**
     * @var string 安装类型
     */
    public $install = 0;

    /**
     * @var UserConnect|null 第三方连接
     */
    private $_connect = null;

    /**
     * @var object 客户端
     */
    private $_client = null;

    /**
     * @inheritdoc
     */
    public function rules() {
        return [
            [['appid', 'sn', 'os', 'build', 'nonce', 'sign', 'timestamp'], 'required'],
            [['build', 'timestamp', 'install'], 'integer'],
            [['sn', 'model'], 'string', 'max' => 64],
            [['os', 'nonce'], 'string', 'max' => 32],
            ['appid', 'validateAppId'],
            ['build', 'validateBuild'],
            ['sign', 'validateSignature'],
        ];
    }

    /**
     * 验证APPID是否为授权应用
     *
     * @param string $attribute `appid`
     */
    public function validateAppId($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        if (!$this->getClient()) {
            $this->addError($attribute, '未授权的应用ID');
        }
    }

    /**
     * 验证Build版本号是否正确
     *
     * @param string $attribute `build`
     */
    public function validateBuild($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        $client = $this->getClient();
        $version = AppVersion::find()->andWhere([
            'and',
            ['build' => $this->build],
            ['client_id' => $client->id],
            ['>', 'status', AppVersion::STATUS_DEFAULT],
        ])->exists();
        if (!$version) {
            $this->addError($attribute, '请求的版本已不提供支持');
        }
    }

    /**
     * 校验请求的签名
     *
     * @param string $attribute `sign`
     */
    public function validateSignature($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        /* @var $security */
        $security = Yii::$app->security;
        $validated = $security->validateSignature($this->attributes, $this->getClient()->secret);
        if ($validated !== true) {
            $tips = '签名校验失败';
            if (YII_DEBUG) {
                $tips .= $validated;
            }
            $this->addError($attribute, $tips);
        }
    }

    /**
     * @param UserConnect|null $connect
     */
    public function setConnect($connect = null) {
        $this->_connect = $connect;
    }

    /**
     * @return UserConnect|null
     */
    public function getConnect() {
        return $this->_connect;
    }

    /**
     * 获取APP授权应用客户端
     *
     * @return AppClient|null
     */
    protected function getClient() {
        if ($this->_client === null) {
            $this->_client = AppClient::findByAppId($this->appid);
        }
        return $this->_client;
    }

    /**
     * 获取OPENID
     *
     * @return string|null
     */
    protected function getOpenid() {
        if ($this->_connect) {
            return $this->_connect->openid;
        }
        return null;
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels() {
        return [
            'appid' => 'AppID',
            'sn' => '设备号',
            'model' => '设备型号',
            'os' => '系统',
            'build' => 'Build',
            'install' => '安装类型',
            'nonce' => '随机串',
            'timestamp' => '时间戳',
            'sign' => '签名',
        ];
    }

    /**
     * 认证授权操作
     *
     * @inheritdoc
     * @throws \common\base\ModelHttpException
     */
    public function authorize() {
        if (!$this->validate()) {
            return $this->validateError('请求数据校验失败');
        }
        return $this->executeTransaction(__FUNCTION__);
    }

    /**
     * 数据保存
     *
     * @inheritdoc
     * @throws Exception|\yii\base\Exception
     */
    protected function transactAuthorize() {
        $device = AppDevice::findOrNew([
            'sn' => $this->sn,
            'os' => $this->os,
            'push_token' => $this->openid,
        ]);
        $device->attributes = [
            'build' => $this->build,
            'model' => $this->model,
        ];
        if (!$device->save()) {
            throw new Exception('设备添加失败' . $device->getErrorMsg());
        }
        $token = AppToken::findOrNew([
            'client_id' => $this->client->id,
            'device_id' => $device->id,
        ]);
        $token->setAttributes([
            'build' => $this->build,
            'os' => $this->os,
        ]);
        if ($this->install) {
            $token->user_id = 0;
        }
        $connect = $this->getConnect();
        if ($connect && $connect->user_id && $token->user_id && $connect->user_id != $token->user_id) {
            $token->user_id = 0;
        }
        $token->generateAccessToken();
        if (!$token->save()) {
            throw new Exception('Token生成失败' . $token->getErrorMsg());
        }
        return $token;
    }

}
